package com.gton.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @description: springboot的RedisTemplate实现分布式锁
 * @author: GuoTong
 * @createTime: 2022-11-27 17:07
 * @since JDK 1.8 OR 11
 **/
@Slf4j
@Component
public class RedisLock {

    @Autowired
    @Qualifier("redisTemplateByMySelf")
    private RedisTemplate<String, Object> redisTemplate;

    private static final String REQUEST_CONTAINER = "REDIS_LOCK";

    /**
     * 锁的过期时间可设置的长一些（业务执行完就释放了），至少要比预计的业务执行时间长（防止业务没执行完就释放了锁）
     */
    private static final long EXPIRE_TIME = 300L;


    /**
     * Description:  尝试获取redis锁
     *
     * @param lockName
     * @author: GuoTong
     * @date: 2022-11-28 09:31:00
     * @return:boolean
     */
    public boolean tryGetLock(String lockName) {

        String key = REQUEST_CONTAINER + lockName;
        // redis获取锁
        boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, 1);
        // 如果没有获取得到
        if (!aBoolean) {
            // 尝试继续获取Redis锁
            try {
                // 等待0.5秒继续尝试获取锁
                Thread.sleep(EXPIRE_TIME);
                aBoolean = redisTemplate.opsForValue().setIfAbsent(key, 1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.error("尝试获取redis锁失败");
            }

        }
        // 如果获取锁成功
        if (aBoolean) {
            // 设置默认过期时间300秒，防止程序出错没有手动释放，就由redis自己释放
            redisTemplate.expire(key, EXPIRE_TIME, TimeUnit.SECONDS);
        }
        return aBoolean;
    }

    /**
     * Description:  手动释放redis锁
     *
     * @param lockName
     * @author: GuoTong
     * @date: 2022-11-28 09:33:45
     * @return:void
     */
    public void shutdownLock(String lockName) {
        String key = REQUEST_CONTAINER + lockName;
        redisTemplate.delete(key);
    }


}

